package com.nhncorp.pleiades.client;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class GenericLockEventHandler implements LockEventHandler {
  public static final Log LOG = LogFactory.getLog(GenericLockEventHandler.class
      .getName());
//  private List<LockEventMonitor> eventMonitors = new ArrayList<LockEventMonitor>();
  private List<EventMonitorWrapper> evtMtrList = new ArrayList<EventMonitorWrapper>();
  
  public GenericLockEventHandler( ) {
  }
  
  class EventMonitorWrapper {
    
    private LockEventMonitor monitor;
    private LockEventFilter filter;
    
    public EventMonitorWrapper(LockEventMonitor m, LockEventFilter f) {
      this.monitor = m;
      this.filter = f;
    }
    public String toString() {
      return this.monitor.toString();
    }
    public LockEventMonitor getMonitor() {
      return monitor;
    }
    public void setMonitor(LockEventMonitor monitor) {
      this.monitor = monitor;
    }
    public LockEventFilter getFilter() {
      return filter;
    }
    public void setFilter(LockEventFilter filter) {
      this.filter = filter;
    }
  }
  
  public void addLockEventMonitor(LockEventMonitor monitor) {
//    synchronized (eventMonitors) {
//      for(LockEventMonitor entry : eventMonitors) {
//        if(entry.equals(monitor)) {
//          return;
//        }
//      }
//      System.out.println(monitor.toString() + ", size: " + eventMonitors.size());
//      eventMonitors.add(monitor); 
//    }
    
    EventMonitorWrapper mtrWrapper = new EventMonitorWrapper(monitor, monitor.getFilter());
    synchronized (evtMtrList) {
      for(EventMonitorWrapper entry : evtMtrList) {
        if(entry.equals(mtrWrapper)) {
          return;
        }
      }
      evtMtrList.add(mtrWrapper); 
    }    
  }
  
  public void removeEventMonitor(LockEventMonitor monitor) {
//    synchronized (eventMonitors) {
//      eventMonitors.remove(monitor);
//    }

    synchronized (evtMtrList) {
      evtMtrList.remove(new EventMonitorWrapper(monitor, monitor.getFilter()));
    }    
  }
  
  private void notifyMonitors(LockService.Events event, LockEventData eventData) {
//    synchronized (eventMonitors) {
//      LOG.debug("notifyMonitors: " + eventData);
//      for (LockEventMonitor monitor : eventMonitors) {
//        try {
//          if( monitor.getFilter().doFilter(eventData) ) {
//            LOG.debug("Succeed to notifyMonitor : " + eventData);
//            monitor.notifyEvent(event, eventData);
//          } else {
//            LOG.debug("Failed to notifyMonitor : " + eventData);
//          }
//        } catch (IOException e) {
//          e.printStackTrace();
//        }
//      }
//    }
    
    synchronized (evtMtrList) {
      LOG.debug("notifyMonitors: " + eventData);
      for (EventMonitorWrapper mtrWrapper : evtMtrList) {
        try {
          if( mtrWrapper.getFilter().doFilter(eventData) ) {
            LOG.debug("Succeed to notifyMonitor : " + eventData);
            mtrWrapper.getMonitor().notifyEvent(event, eventData);
          } else {
            LOG.debug("Failed to notifyMonitor : " + eventData);
          }
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
  }
  
  
  public void contentsModified(LockEventData eventData) {
    notifyMonitors(LockService.Events.CONTENTS_CHANGED, eventData);
  }

  
  public void lockExpired(LockEventData eventData) {
    notifyMonitors(LockService.Events.LOCK_EXPIRED, eventData);
  }

  
  public void masterFailover() {
    
  }

  
  public void nodeAdded(LockEventData eventData) {
    notifyMonitors(LockService.Events.NODE_ADDED, eventData);
  }

  
  public void nodeModified(LockEventData eventData) {
    notifyMonitors(LockService.Events.NODE_MODIFIED, eventData);
  }

  
  public void nodeRemoved(LockEventData eventData) {
    notifyMonitors(LockService.Events.NODE_REMOVED, eventData);
  }
  
  
  public void clientExpired(LockEventData eventData) {
    notifyMonitors(LockService.Events.CLIENT_EXPIRED, eventData);
  }  

  
  public void sessionExpired() {

  }

  
  public void sessionSafe() {

  }

  
  public void sessionWarning() {

  }

  public void clearLockEventMonitors() {
    synchronized(evtMtrList) {
      evtMtrList.clear();
    }
  }
}
